\chapter{Данные}
\pagenumbering{arabic}

\section{EXIF теги в Linux}
В различных форматах графических файлов возможность хранить дополнительные сведения, например, время выдержки, значение диафрагмы, время или ещё что-нибудь. Это обеспечивает формат EXIF (Exchangeable Image File Format). В Linux для работы с тими EXIF данными есть такой мощный пакет утилит, как exiftools, всю полезность которого автор этих строк испытал на себе. Вот, например, потребовалось вам сохранить какие-то пометки о том, где сделан этот снимок - тут-то вам exiftools и пригодится.

Например, выдираем теги из RAW-файла на примере цифровой камеры Canon EOS 400D 

exiftool \verb+IMG_0383.CR2+ :

\begin{lstlisting}
exiftool IMG_0383.CR2
ExifTool Version Number : 6.57
File Name : IMG_0383.CR2
File Size : 8 MB
File Modification Date/Time : 2008:10:22 12:48:10
File Type : CR2
MIME Type : image/x-raw
Image Width : 1936
Image Height : 1288
Bits Per Sample : 8 8 8
<....>
\end{lstlisting}



Например, чтобы выцедить из RAW-файла время выдержки, сделать надо вот что:

\begin{lstlisting}
exiftool -shutterspeed IMG_0383.CR2
Shutter Speed : 1
\end{lstlisting}


Для того, чтобы использовать exif-теги, надо запросить список тегов в которые возможна запись. Пишем:

\begin{lstlisting}
$ exiftool -listw IMG_0383.CR2
\end{lstlisting}



Так, например из кучи тегов мы хотим писать в тег City. Для этого:

\begin{lstlisting}
$ exiftool -City=Moscow IMG_0383.CR2
1 image files updated
\end{lstlisting}


И теперь:

\begin{lstlisting}
$ exiftool -City IMG_0383.CR2
City : Moscow
\end{lstlisting}



Ура, теперь мы в тег City записали, что хотели. Утилита exiftools может не только читать, но и записывать информаицю в EXIF-теги. Это может быть полезно и нужно для хранения в RAW-файлах информации о съёмке.

И теперь, чтобы избавить себя от нервотрёпки, делаем так: находим любой записываемый тег, и пишем туда то, что относится к эксперименту. После этого записываем нужные данные во ВСЕ файлы RAW скопом:

\begin{lstlisting}
$ exiftool -City='Moscow' *.CR2
10 image files updated
\end{lstlisting}


С удовлетворением видим:

\begin{lstlisting}
$ exiftool -City *.CR2
======== IMG_0383.CR2
City : Moscow
\end{lstlisting}



\section{Небольшая шпаргалка по командам SVN}
В этом посте я решил собрать простые и наиболее часто используемые мной команды svn, часть параметров и способов работы с репозиториями svn, которых я склонен забывать.

\subsection{Наполнение репозитория Subversion}
Репозиторий, созданный командой:

\begin{lstlisting}
$ svnadmin create /usr/local/svn/newrepos
\end{lstlisting}


нужно наполнить свежими данными. Для этого есть команда svn import это быстрый способ скопировать не версионированное дерево файлов в хранилище, например:

\begin{lstlisting}
$ svn import mytree file:///usr/local/svn/newrepos/some/project \
-m "Initial import"
Adding mytree/foo.c
Adding mytree/bar.c
Adding mytree/subdir
Adding mytree/subdir/quux.h

Committed revision 1.
\end{lstlisting}



Стоит заметить, что после завершения импорта, оригинальное дерево файлов не конвертируется в рабочую копию. Для того, чтобы начать работать вам необходимо создать новую рабочую копию (svn checkout) дерева файлов.


\subsection{Добавление новых файлов и каталогов в репозиторий Subversion}
Например, вы создаёте крупный документ в ЛаТеХе, и появился новый каталог с новыми текстами или картинками. Как их добавить в Subversion репозиторий? Очень просто:

\begin{lstlisting}
$ svn add temp A temp A temp/Lit_obzor2_edt.tex
\end{lstlisting}

Теперь смотрим на статус наших файлов и видим, что против них стоит буква А - значит, они Added, то есть добавлены:

\begin{lstlisting}
$ svn status
? image
? biblio
? optcodeimages
M draft_PhD_Konnik.dvi
! PhD_Konnik.log
A temp
A temp/Lit_obzor2_edt.tex
! PhD_Konnik.toc
M PhD_Konnik_chapter_results.tex~
! PhD_Konnik_chapter_introduction.dvi
! PhD_Konnik.aux
! PhD_Konnik.bbl
! draft_PhD_Konnik.log
! PhD_Konnik.blg
! draft_PhD_Konnik.toc
! draft_PhD_Konnik.aux
! draft_PhD_Konnik.bbl
M PhD_Konnik.dvi
! draft_PhD_Konnik.blg
M PhD_Konnik_chapter_results.tex
! PhD_Konnik_chapter_introduction.log
\end{lstlisting}

Они будут помещены в репозиторий при следующей отправке (commit).


\subsection{Обновление рабочей копии до состояния репозитория}
Файлы, находящиеся в репозитории свежее, чем у вас в рабочей копии. Дубовый вариант заключается в том, чтобы удалить свою рабочую копию и сделать chekout из репозитория. Это проходит, если репозиторий только ваш и вы уверены, что никаких изменений в рабочей копии вы не потеряете. Но есть вариант и получше:


\begin{lstlisting}
$ svn update U
biblio/my.bib U
biblio/my.bib.bak
Updated to revision 9.
\end{lstlisting}


Это обновит вашу локальную копию до ревизии, которая находится в репозитории SVN. После этого можно приступать к работе с файлами, так как они обновлены до последней версии.

Латинские буквы перед именем файла имеют свой сакральный смысл, скрытый в недрах документации сокрушительных размеров (кстати, документация очень хороша, и есть даже частичный перевод на русский тут). Собственно, буква означает действие, которое выполнил Subversion для приведения рабочей копии в актуальное состояние:

\begin{framed}
\begin{lstlisting}
U foo

    Updated - %Файл foo был обновлен%

A foo

    Added - %Файл или директория foo% 
    %были добавлены в рабочую копию.%

D foo

    Deleted - %Файл или директория foo %
    %были удалены из рабочей копии.%

R foo

    Replaced - %Файл или директория foo %
    %была заменена в рабочей копии; это значит, %
    %что foo был удален, а новый элемент с %
    %таким же именем был добавлен.%

G foo

    merGed - %Файл foo получил новые изменения %
    %из хранилища, однако ваша локальная копия %
    %содержит ваши изменения. Либо изменения %
    %не пересекаются, либо они точно такие же,%
    %как ваши локальные изменения, поэтому %
    %Subversion успешно выполнил слияние изменений %
    %хранилища с файлом.%

C foo

    Conflicting - %Файл foo получил от сервера %
    %конфликтующие изменения. Изменения с сервера %
    %пересекаются с вашими изменениями фала.%
\end{lstlisting}
\end{framed}



\subsection{Просмотр истории ревизий в Subversion}
Часто нужно просмотреть, что и как редактировалось - для этого при отправке новых данных в репозиторий (commit) есть смысл писать содержательные и осмысленные комментарии. Если это так, то можно многое узнать о том, что и когда редактировалось:

\begin{lstlisting}
$ svn log --revision 1:3
\end{lstlisting}


что значит: выдать лог ревизий с первую по третью. Увидим:

\begin{lstlisting}
-------
r1 | penta4 | 2008-06-03 15:49:21 +0400 (%Втр%, 03 %Июн% 2008) | 1 line Initial dissertation state

-------
r2 | penta4 | 2008-06-03 16:56:01 +0400 (%Втр%, 03 %Июн% 2008) | 3 lines Committed new editions

-------
r3 | penta4 | 2008-06-03 16:58:12 +0400 (%Втр%, 03 %Июн% 2008) | 2 lines incremental -------
\end{lstlisting}


Очень удобно, когда нужно кому-то отправить историю правок вашей программы или документа.


\subsection{Просмотр изменений в Subversion}
Например, нужно просмотреть изменения, происшедшие со второй по четвёртую ревизии. Легко!

\begin{lstlisting}
$ svn diff --revision 2:4 PhD_Konnik.tex > PhD_Konnik.tex.diff.r2-4
\end{lstlisting}

Это выведет нам в diff-файл все изменения, а ваш любимый текстовый редактор их с удовольствием подсветит для более удобного просмотра.



\subsection{Отмена изменений в Subversion}
Вы сидите и правите какой-то документ - и тут с ужасом понимаете, что правите \textit{не тот} документ. Не беда - переносите изменения во временный файл, а для того документа, который вы нечаянно испортили, пишем:

\begin{lstlisting}
$ svn revert UMNIK08-Report-01/Report-01-sub1-shortened.tex
Reverted 'UMNIK08-Report-01/Report-01-sub1-shortened.tex'
\end{lstlisting}


После этого SVN вернёт файл Report-01-sub1-shortened.tex в то состояние, в котором он находится в репозитории.


\subsection{Копирование или перемещение нескольких файлов в SVN/Subversion (multiple targets move/copy in SVN)}
Странно, однако SVN не понимает символов типа *, так что ваша попытка сделать так:

\begin{lstlisting}
$ svn mv MCBC/*jpg LinuxImages/
\end{lstlisting}


приведёт к ошибке:

\begin{lstlisting}
svn: Client error in parsing arguments
\end{lstlisting}


Чтобы не перемещать все файлы по одному, воспользуемся Bash:

\begin{lstlisting}
for i in *.cs ; do svn mv $i newFolder/ ; done
\end{lstlisting}


Конечно, если в вашей операционной системе есть нормальная консоль :-)


\subsection{Выдача определённой правки файла из репозитория}
Например, нам очень нужно посмотреть, каким был файл при второй правке. Для этого пишем:

\begin{lstlisting}
$ svn cat --revision 2 PhD_Konnik.tex > PhD_Konnik.tex.v2
\end{lstlisting}


То есть выводим результат второй правки файла PhD\verb+_+Konnik.tex и записываем его в файл PhD\verb+_+Konnik.tex.v2 для дальнейшего просмотра.

\subsection{Восстановление удалённых файлов в Subversion}
Ну и наконец самое страшное: вы приказали Subversion удалить файл из репозитория, а потом кто-то вам говорит: этот файл нужно вернуть. На самом деле, файл, который вы удалили из SVN, никуда не делся: элемент исчезает из правки HEAD, но продолжает существовать в более ранних правках. Так что вопрос "как восстановить удалённый файл в Subversion" имеет довольно простой ответ: скопировать его из последней правки, где он был.

Главное вспомнить, как этот файл назывался. Если помним хотя бы частично имя файла (например, overview), то можно попросить Subversion вывести все упоминания о правках этого файла так:

\begin{lstlisting}
svn log -v | grep spatialcoh -A 5 -B 5 
\end{lstlisting}


Здесь параметры для grep такие: -A 5 это выдача 5 строк после (After) совпадения, -B 5 это 5 строк до (Before) совпадения. Получим длинный вывод вида:

\begin{lstlisting}
spatialcoherencyexplained.eps 436 | penta4 | 
2009-12-02 15:39:30 +0300 (Срд, 02 Дек 2009) | 2 lines
Changed paths:
M /PhD_Konnik_autoreferat.tex
M /PhD_Konnik_chapter_opticalcoding.tex
M /PhD_Konnik_chapter_overview.tex
D /images-opticalcoding/spatialcoherencyexplained.eps
M /images-opticalcoding/sxemacorrelator3.eps
M /latex.py
M /svnstatus.tex
M /zagashnikPhD_Konnik.tex

--
M /biblio
A /formaldocs/disserDocs.tif.7z
A /images-opticalcoding/PSFdotssize.eps
M /images-opticalcoding/PSFoutofLambdaDelta
LambdavsfromNumberOfElementsPSFRus.ps
A /images-opticalcoding/auxilaryImagesForDisser.svg
A /images-opticalcoding/spatialcoherencyexplained.eps
M /zagashnikPhD_Konnik.tex

TENGIBLE changes:
- autoreferat is improved slightly;
- Spatial coherency is improved
\end{lstlisting}


Красным подчеркнул я: видно, что файл spatialcoherencyexplained.eps удалён в правку 436, и теперь хотим его восстановить. Смотрим, в какой правке файл был удалён - в 436, значит, в 435 есть его последняя копия. Восстанавливаем:

\begin{lstlisting}
svn copy --revision 435 file:///phdthesis/images-opticalcoding/spatialcoherencyexplained.eps spatialcoherencyexplained.eps
\end{lstlisting}


Всё, теперь файл появится снова, вместе с историей правок (что важно) и вы можете его править дальше.


\section{Вертикальная конкатенация двух файлов}
Обработанные экспериментельные данные часто представляют собой ряды чисел, по которым затем небходимо строить графики. Иногда требуется склеить данные из двух источников так, чтобы новые данные были дополнительными столбцами в уже существующих данных.

Есть данные A:

\begin{lstlisting}
$ cat RAWMAXmeasurementresult
2.7100000e+02 2.8300000e+02 2.8000000e+02
2.7300000e+02 2.8700000e+02 2.8400000e+02
2.7400000e+02 2.9600000e+02 2.9000000e+02
2.7800000e+02 3.0400000e+02 2.9800000e+02
\end{lstlisting}



Есть другой файл с данными B, полученный обработкой результата эксперимента в другой программе:

\begin{lstlisting}
$ cat shutter
.00024414062500000000
.00031661600810536980
.00037652020030874656
.00048828125000000000
\end{lstlisting}


Нужно сделать так, чтобы в результате получился файл типа:

\begin{lstlisting}
2.7100000e+02 2.8300000e+02 2.8000000e+02 .00024414062500000000
2.7300000e+02 2.8700000e+02 2.8400000e+02 .00031661600810536980
2.7400000e+02 2.9600000e+02 2.9000000e+02 .00037652020030874656
2.7800000e+02 3.0400000e+02 2.9800000e+02 .00048828125000000000
\end{lstlisting}


Так проще строить графики в гнуплоте, что в скриптах реализуется сравнительно просто.

Условия:

1. Ряды A и B можно перемещать, но нежелательно менять местами данные в ряде А.

2. Решение должно предполагать автоматизированную обработку (данных очень много, Ексель / ОпенОфис Calc отпадают).

3. Ряд B получается не напрямую, сделать всё в одной программе нельзя.

4. Разделители - пробелы (количество неважно).

5. Задача не надуманная.

Что требуется:

Скрипт/программа, делающая такую конкатенацию, максимально кроссплатформенная (никаких вижуал васиков), ориентированная на *nix-среду.


Решение:
Изумительное по краткости и лаконичности: использование команды paste.

\begin{lstlisting}
$ paste -d " " RAWMAXmeasurementresult shutter > sult
\end{lstlisting}


И вся любовь.


\section{Как сделать бекап при помощи dd}
Для того, чтобы сделать backup (бэкап, резервная копия) винчестера для последующего восстановления вовсе не нужны коммерческие, проприетарные утилиты - есть старый, как мир, dd. С помощью dd очень удобно и просто делать бекапы, и всё, что нужно сделать - просто правильно его использовать.

\subsection{Приготовления}
Загружаемся с любого LiveCD диска с Linux / BSD, залогиниваемся под root-аккаунтом.
Убеждаемся, написав в консоли df, что ни один из тех разделов, что мы собираемся копировать, не примонтирована на запись. Решаем, куда будем архивировать данные: это может быть другой раздел на винчестере, внешний жёсткий диск или по сети.


\subsection{Создаём резервную копию}
В данном примере /dev/hda это винчестер, который архивируем, а /dev/sda1 - это раздел внешнего винчестера или другая партиция, на которую архивируем, hda.img.gz - получившийся сжатый файл-образ.

\subsubsection{Внешний винчестер или другой раздел диска}
Монтируем устройство, куда мы будем архивировать данные
\begin{lstlisting}
# mount -t vfat /dev/sda1 /mnt/sda1
\end{lstlisting}


Перегоняем данные с одного винчестера на другой. Так как данных много, полезно их сжать - и никс-системы позволяют это делать "на лету". В примере использван GZip, но подойдёт и любой другой (например, bzip2 или p7zip).
Для этого:

\begin{lstlisting}
# dd if=/dev/hda conv=sync,noerror bs=64K | gzip -c > /mnt/sda1/hda.img.gz
\end{lstlisting}


Здесь происходит архивирование с одновременным сжатием, результат чего записывается в файл hda.img.gz

Параметр "conv=sync,noerror" указывает dd не читать блок, если при этом происходит ошибка, но записать в архивируемый файл-образ данные, чтобы размер блока не менялся.

Параметр "bs=64K" это размер блока в килобайтах - использование такого большого размера блока ускоряет процесс копирования. Параметр bs можно сделать ещё больше, а именно равным размеру кеша копируемого диска (например bs=8m), это сильно ускорит весь процесс.

Выходной поток передаётся по конвейеру для сжатия gzip, результат выводится в файл на другом диске.

\subsubsection{2.2 Удалённо по сети}
Всё то же самое, что в п.2.1, но с добавлением в конвейер SSH:
\begin{lstlisting}
# dd if=/dev/hda conv=sync,noerror bs=64K | gzip -c | ssh -c blowfish user@hostname "dd of=hda.img.gz bs=64k"
\end{lstlisting}

Архивный файл появится в домашней директории пользователя user на машине hostname. Если сеть маленькая, лучше вместо hostname использовать просто ip-адрес. Опция -c blowfish заставляет SSH выбрать алгоритм шифрования Blowfish, который быстрее остальных шифрует данные.

Вариант с netcat, если данные копируются по локальной сети и шифрование не нужно:

\begin{lstlisting}
# dd if=/dev/hda conv=sync,noerror bs=64K | gzip -c | nc 192.168.1.1 3333
\end{lstlisting}


На удалённой машине должен быть запущен netcat:
\begin{lstlisting}
# nc -l -p 3333 > hda.img.gz
\end{lstlisting}


Вариант с SAMBA, если копирование производится на оффтопичную машину: примонтировать удалённо сетевой ресурс
\begin{lstlisting}
 smbmount //192.168.1.100/shared /mnt/remoteshare -o username=USERNAME,password=PASSWORD
\end{lstlisting}

и далее всё то же, что и в п.2.1.


\subsection{Восстанавливаем данные из бекапа}
Пример тот же: /dev/hda это винчестер, который архивируем, hda.img.gz - архивный сжатый файл-образ, а /dev/sda1 - это раздел внешнего винчестера или другая партиция, с которого восстанавливаем данные.

\subsubsection{Внешний винчестер или другой раздел диска}
Копируем и распаковываем файл-образ одновременно:
\begin{lstlisting}
# gzip -x /mnt/sda1/hda.img.gz | dd of=/dev/hda conv=sync,noerror bs=64K 
\end{lstlisting}


Все параметры в п.2 уже объяснены.

\subsubsection{Удалённо по сети}
Сетевой вариант с восстановлением из файл-образа:
\begin{lstlisting}
# dd if=hda.img.gz | ssh -c blowfish user@deadhost "gunzip -c | dd of=/dev/hda1 bs=64k"
\end{lstlisting}


Следует помнить, что в данном случае не следует использовать опцию conv=sync,noerror в опциях dd - если вы всё-таки включите эту опцию, в большинстве случаев это исказит записываемые данные (это заставляет dd не дожидаться данных, приходящих по сети, если целый блок недоступен).



\section{Subversion - быстрый старт}
Вы пишете программу на любом языке программирования или просто новую статью в латехе. В порыве вдохновения лихо правите текст, забывая о бекапах между изменениями. И тут вспомнаете, что часть текста вчера удалили зря. Резервных копий нет, а текст был хорош... И тут время ставить систему контроля версий - например, Subversion. О том, как поставить и настроить Subversion в Linux, написан этот пост.

\subsection{Как быстро поставить и использовать систему контроля версий?}
На самом деле, в этом нет ничего сложного. Итак, возьмите вашу латеховскую статью / скрипт / исходник программы и попробуйте. Для того, чтобы быстро поставить Subversion (она же SVN) и воспользоваться всеми её благами, нужно выполнить несколько простых шагов.

\subsubsection{Ставим Subversion и оболочку для неё}
Хотя с системой контроля версий удобнее работать через консоль, графическая оболочка не помешает (можно визуально наблюдать изменения, сравнивать правки и прочее). Ставим:

\begin{lstlisting}
# aptitude install kdesvn svn
\end{lstlisting}


и все зависимости (здесь рассматривается svn v.1.4.2 из Debian GNU/Linux Etch). Через мгновение у нас уже будет установлена Subversion. Полдела сделано!


\subsubsection{Начало работы с Subversion - импорт файлов в репозиторий}
Первым делом нужно создать новый репозиторий - простой, без особых затей и канделябров:

\begin{lstlisting}
$ svnadmin create phdthesis
\end{lstlisting}


В текущем каталоге появится подкаталог phdthesis следующего содержания:

\begin{lstlisting}
drwxr-xr-x 2 penta4 penta4 32768 2008-06-03 15:48 conf
drwxr-xr-x 2 penta4 penta4 32768 2008-06-03 15:48 dav
drwxr-xr-x 5 penta4 penta4 32768 2008-06-03 18:55 db
-r--r--r-- 1 penta4 penta4 2 2008-06-03 15:48 format
drwxr-xr-x 2 penta4 penta4 32768 2008-06-03 15:48 hooks
drwxr-xr-x 2 penta4 penta4 32768 2008-06-03 15:48 locks
-rw-r--r-- 1 penta4 penta4 229 2008-06-03 15:48 README.txt
\end{lstlisting}


Красным подсвечены важные для нас каталоги: conf содержит конфигурационный файл репозитория (сейчас мы его немного допилим), а db содержит версии наших данных.

Наш репозиторий предполагается локальным, то есть доступа по сети к репозиторию нет и не надо. Тогда нужно конфиг немного допилить. Редактируем файл phdthesis/conf/svnserve.conf для того, чтобы у нас не было проблем с записью туда новых файлов - для этого ищем строку anon-access и правим:

\begin{lstlisting}
anon-access = write
\end{lstlisting}

Теперь любой аноним имеет права на запись в наш репозиторий - то есть вам не нужно ломать себе голову авторизацией и паролями (если, конечно, с проектом работаете вы один).

Так, репозиторий создали, теперь его нужно наполнить данными. Для этого переходим в каталог, где хранятся нужные данные, и даём команду:

\begin{lstlisting}
$ svn import -m "Initial dissertation state" file:///mnt/flash/other/phdthesis/
\end{lstlisting}

Здесь указывается полный путь до репозитория. Каждый раз указывать его не нужно - скоро мы поднимем SVN-сервер одной левой, и наша жизнь станет ещё веселее.

При импорте файлов Subversion будет выводить в консоль имена добавляемых файлов:

\begin{lstlisting}
Adding chapter.dtx
Adding kvoptions.ins
Adding (bin) draft_PhD_Konnik.dvi
Adding PhD_Konnik_chapter_introduction.tex
Adding PhD_Konnik_chapter_introduction.tex.backup
Adding (bin) PhD_Konnik_chapter_introduction.dvi
Adding PhD_Konnik.tex

Committed revision 1.
\end{lstlisting}

То есть команда svn import берёт содержимое текущего каталога и помещает его в репозитарий, а так же все вложенные каталоги, если они есть. При этом выводится номер ревизии - это 1, наша первая правка.


\subsubsection{Извлекаем и загружаем изменённые файлы в репозиторий}
Для того, чтобы начать работать с файлами, переходим в какой-нибудь другой каталог и просим Subversion выдать нам последнюю копию из репозитория. Делается это так:

\begin{lstlisting}
$ svn checkout file:///mnt/flash/other/phdthesis/
\end{lstlisting}


в результате чего в текущем каталоге получим локальную копию данных из репозитория.

После внесения нужных правок, загружаем результаты обратно в репозиторий, для чего выполняем команду в каталоге, где находится рабочая копия данных, с которыми работали:

\begin{lstlisting}
$ svn commit --message "minor edition in tex-files"
\end{lstlisting}

После ключа --message пишем в кавычках короткое сообщение, чтобы отличать одну правку от другой. В процессе загрузки изменений Subversion будет выводить имена файлов, которые загружаются:

\begin{lstlisting}
Sending PhD_Konnik.tex
Sending draft_PhD_Konnik.tex
Transmitting file data ..
Committed revision 2
\end{lstlisting}

% % Лицензия на материалы этого текста
% 
% Материалы сайта "Записки дебианщика" написаны virens и доступны на условиях лицензии Creative Commons Attribution-Non-Commercial-Share Alike 3.0 Unported License. Вы можете копировать, распространять, показывать эту работу, и создавать производные работы в некоммерческих целях на условиях:
% 
% 1) обязательной ссылки на автора (virens, http://mydebianblog.blogspot.com/) и
% 
% 2) распространении любых производных работ на условиях этой же лицензии (ссылка на эту лицензию 
% обязательна!).
% 
% Пожалуйста соблюдайте условия лицензии.
% 
% This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. 
Готово! Ревизия изменённых файлов зарегистрирована в репозитории. Вот так легко и просто начать работать с Subversion.
